package com.lagou.server;

import com.lagou.server.config.RPCServerConfig;
import com.lagou.server.handler.UserServerHandler;
import com.lagou.server.service.decoder.RpcDecoder;
import com.lagou.server.service.entity.RpcRequest;
import com.lagou.server.service.serializer.JSONSerializer;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class ServerBootstrap implements CommandLineRunner {

    public static void main(String[] args) throws InterruptedException {
        SpringApplication.run(ServerBootstrap.class, args);
    }

    @Autowired
    private UserServerHandler userServerHandler;

    @Autowired
    private RPCServerConfig rpcServerConfig;


    @Override
    public void run(String... args) throws Exception {
        int num = Integer.parseInt(args[0]);
        System.out.println("启动Netty服务端，并监听端口：" +( rpcServerConfig.getPort() + num ));
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        io.netty.bootstrap.ServerBootstrap serverBootstrap = new io.netty.bootstrap.ServerBootstrap();
        serverBootstrap.group(bossGroup,workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new StringEncoder());
//                        pipeline.addLast(new StringDecoder());
                        pipeline.addLast(new RpcDecoder(RpcRequest.class, new JSONSerializer()));
                        pipeline.addLast(userServerHandler);
                    }
                });


        serverBootstrap.bind("127.0.0.1", rpcServerConfig.getPort() + num).sync();

        // 注册服务到zookeeper
        registerRpcServerToZk(num);
    }

    private void registerRpcServerToZk(int num) {

        System.out.println("注册RPC服务到ZK上，zk地址：" +
                rpcServerConfig.getRegisterZkUrl() + "\n注册路径为：" + rpcServerConfig.getRegisterBasePath());
        String connectString = rpcServerConfig.getRegisterZkUrl();
        int sessionTimeoutMs = 10000;
        int connectionTimeoutMs = 10000;
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);

        CuratorFramework client = CuratorFrameworkFactory
                .builder().connectString(connectString)
                .sessionTimeoutMs(sessionTimeoutMs)
                .connectionTimeoutMs(connectionTimeoutMs)
                .retryPolicy(retryPolicy).build();

        client.start();
        String registerBasePath = rpcServerConfig.getRegisterBasePath();
        try {
            Stat stat = client.checkExists().forPath(registerBasePath);
            if(stat != null){
                System.out.println("注册根地址已经存在");
            } else {
                System.out.println("注册根地址不存在，则新创建");
                String createPath = client.create()
                        .creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(registerBasePath);
                System.out.println("在ZK创建RPC服务注册根节点：" + createPath);
            }
            // 在根节点下创建服务的临时顺序节点
            String rpcServerContent = "localhost:" + (rpcServerConfig.getPort() + num);
            String registerPath = client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                    .forPath(registerBasePath + "/userService", rpcServerContent.getBytes("GBK"));
            System.out.println("RPC服务信息注册到ZK上，节点为：" + registerPath);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}
